//
// Created by shaun on 8/5/2025.
//

#include <QLabel>
#include <QTimer>
#include <QCoreApplication>
#include <iostream>

#include "props.h"
#include "control_panel.h"

namespace eintik::presentation::panel
{

ControlPanel::ControlPanel(QWidget* parent) : QWidget(parent)
{

    // Focal Law
    focal_law_layout_ = new QGridLayout();

    kStartElement = new QSpinBox(this); //首晶片
    kStartElement->setRange(1,128);
    kStartElement->setValue(1);

    kGapElement = new QDoubleSpinBox(this);//晶片间隙
    kGapElement->setValue(1.0);

    kEndElement = new QSpinBox(this); //末晶片
    kEndElement->setRange(1,128);
    kEndElement->setValue(128);

    kGainDb = new QDoubleSpinBox(this); //增益
    kGainDb->setRange(0,120);
    kGainDb->setValue(30.0);

    kPaVoltage = new QSpinBox(this); //激发电压
    kPaVoltage->setRange(20,100);
    kPaVoltage->setValue(50);

    kAperture = new QSpinBox(this);  //孔径
    kAperture->setValue(1);

    kPulseWidthNs = new QSpinBox(this); //脉冲宽度
    kPulseWidthNs->setRange(10,1200);
    kPulseWidthNs->setValue(50);

    kStep = new QSpinBox(this); //扫查步距
    kStep->setValue(1);

    kFrameRate = new QSpinBox(this); //采集帧率
    kFrameRate->setValue(88);
    kFrameRate->setRange(1, 10000);

    kScanStartUs = new QDoubleSpinBox(this); //范围起点
    kScanStartUs->setRange(0.0, 1e9);
    kScanStartUs->setValue(0.0);

    kScanRangeUs = new QDoubleSpinBox(this); //范围终点
    kScanRangeUs->setRange(1.0, 1e9);
    kScanRangeUs->setValue(10.0);

    kWaveSpeed = new QSpinBox(this);  //声速
    kWaveSpeed->setRange(1, 10000);
    kWaveSpeed->setValue(5920);

    kSampleQty = new QSpinBox(this); //采样点数
    kSampleQty->setRange(1, 100000);
    kSampleQty->setValue(512);

    kGateAStart = new QDoubleSpinBox (this); //闸门A起点
    kGateAStart->setValue(0.0);

    kGateAEnd = new QDoubleSpinBox(this); //闸门A终点
    kGateAEnd->setRange(1,1000.0);
    kGateAEnd->setValue(100.0);

    kGateBStart = new QDoubleSpinBox (this); //闸门B起点
    kGateBStart->setValue(0.0);

    kGateBEnd = new QDoubleSpinBox(this); //闸门B终点
    kGateBEnd->setRange(1,1000.0);
    kGateBEnd->setValue(100.0);

    kGateIHight = new QDoubleSpinBox(this); // 闸门I高度
    kGateIHight->setRange(0, 100);
    kGateIHight->setValue(50.0);

    kCScanInterval = new QDoubleSpinBox(this);//C窗口大小
    kCScanInterval->setRange(0, 1e9);
    kCScanInterval->setValue(100.0);

    kBeamLocation = new QSpinBox(this);//beam位置
    kBeamLocation->setRange(1,128);
    kBeamLocation->setValue(10);

    kStartTypeCombox = new QComboBox(this);
    kStartTypeCombox->addItem("时间编码");
    kStartTypeCombox->addItem("编码器编码");
    kStartTypeCombox->setCurrentIndex(1);

    kStartParamSpinBox  = new QSpinBox(this);
    kStartParamSpinBox ->setRange(0,10000);
    kStartParamSpinBox ->setValue(500);

    // Layout for focal law parameters
    focal_law_layout_->addWidget(new QLabel("首晶片:", this), 0, 0);
    focal_law_layout_->addWidget(kStartElement, 0, 1);

    focal_law_layout_->addWidget(new QLabel("晶片间隙:", this), 1, 0);
    focal_law_layout_->addWidget(kGapElement, 1, 1);

    focal_law_layout_->addWidget(new QLabel("末晶片:", this), 2, 0);
    focal_law_layout_->addWidget(kEndElement, 2, 1);

    focal_law_layout_->addWidget(new QLabel("增益:", this), 3, 0);
    focal_law_layout_->addWidget(kGainDb, 3, 1);

    focal_law_layout_->addWidget(new QLabel("激发电压:", this), 4, 0);
    focal_law_layout_->addWidget(kPaVoltage, 4, 1);

    focal_law_layout_->addWidget(new QLabel("脉冲宽度:", this), 5, 0);
    focal_law_layout_->addWidget(kPulseWidthNs, 5, 1);

    focal_law_layout_->addWidget(new QLabel("采集帧率:", this), 6, 0);
    focal_law_layout_->addWidget(kFrameRate, 6, 1);

    focal_law_layout_->addWidget(new QLabel("范围起点:", this), 7, 0);
    focal_law_layout_->addWidget(kScanStartUs, 7, 1);

    focal_law_layout_->addWidget(new QLabel("范围:", this), 8, 0);
    focal_law_layout_->addWidget(kScanRangeUs, 8, 1);

    focal_law_layout_->addWidget(new QLabel("声速:", this), 9, 0);
    focal_law_layout_->addWidget(kWaveSpeed, 9, 1);

    focal_law_layout_->addWidget(new QLabel("采样点数:", this), 10, 0);
    focal_law_layout_->addWidget(kSampleQty, 10, 1);

    focal_law_layout_->addWidget(new QLabel("闸门I高度:", this), 11, 0);
    focal_law_layout_->addWidget(kGateIHight, 11, 1);

    focal_law_layout_->addWidget(new QLabel("闸门A起点:", this), 12, 0);
    focal_law_layout_->addWidget(kGateAStart, 12, 1);

    focal_law_layout_->addWidget(new QLabel("闸门A终点:", this), 13, 0);
    focal_law_layout_->addWidget(kGateAEnd, 13, 1);

    focal_law_layout_->addWidget(new QLabel("闸门B起点:", this), 14, 0);
    focal_law_layout_->addWidget(kGateBStart, 14, 1);

    focal_law_layout_->addWidget(new QLabel("闸门B终点:", this), 15, 0);
    focal_law_layout_->addWidget(kGateBEnd, 15, 1);

    focal_law_layout_->addWidget(new QLabel("C窗口大小:",this),16,0);
    focal_law_layout_->addWidget(kCScanInterval,16,1);

    focal_law_layout_->addWidget(new QLabel("BeamID:",this),17,0);
    focal_law_layout_->addWidget(kBeamLocation,17,1);

    focal_law_layout_->addWidget(new QLabel("编码类型:", this), 18, 0);
    focal_law_layout_->addWidget(kStartTypeCombox, 18, 1);

    focal_law_layout_->addWidget(new QLabel("编码延迟:", this), 19, 0);
    focal_law_layout_->addWidget(kStartParamSpinBox, 19, 1);

    focal_law_layout_->setSpacing(5);

    // Control Buttons
    control_layout_ = new QGridLayout();
    config_btn_ = new QPushButton("Config", this);
    set_btn_ = new QPushButton("Set", this);
    start_btn_ = new QPushButton("Start", this);
    stop_btn_ = new QPushButton("Stop", this);

    // Layout for control buttons
    control_layout_->addWidget(config_btn_, 0, 1);
    control_layout_->addWidget(set_btn_, 0, 2);
    control_layout_->addWidget(start_btn_, 1, 1);
    control_layout_->addWidget(stop_btn_, 1, 2);
    control_layout_->setSpacing(20);

    // Network and Debug Layouts
    network_layout_ = new QGridLayout();
    connect_btn_ = new QPushButton("Connect", this);
    close_btn_ = new QPushButton("Close", this);

    // Layout for network buttons
    network_layout_->addWidget(connect_btn_, 0, 0);
    network_layout_->addWidget(close_btn_, 0, 1);
    network_layout_->setSpacing(20);

    debounce_timer_ = new QTimer(this);
    debounce_timer_->setInterval(1000);
    debounce_timer_->setSingleShot(true);

    QObject::connect(debounce_timer_, &QTimer::timeout, this, &ControlPanel::EmitParameterChanged);

    SetWidgetBinding(eintik::kStartElement, KStartElement());                                   //首晶片
    SetWidgetBinding(eintik::kEndElement, KEndElement());                                       //末晶片
    SetWidgetBindingDouble(eintik::kGainDb, KGainDb());                                         //增益
    SetWidgetBinding(eintik::kPaVoltage, KPaVoltage());                                         //激发电压
    SetWidgetBinding(eintik::kAperture, KAperture());                                           //孔径
    SetWidgetBinding(eintik::kPulseWidthNs, KPulseWidthNs());                                   //脉冲宽度
    SetWidgetBinding(eintik::kStep, KStep());                                                   //扫查步距
    SetWidgetBinding(eintik::kFrameRate, KFrameRate());                                         //采集帧率
    SetWidgetBindingDouble(eintik::kScanStartUs, KScanStartUs());                               //范围起点
    SetWidgetBindingDouble(eintik::kScanRangeUs, KScanRangeUs());                               //范围终点
    SetWidgetBinding(eintik::property::kWaveSpeed,KWaveSpeed());                                //声速
    SetWidgetBinding(eintik::kSampleQty,KSampleQty());                                          //采样点数
    SetWidgetBindingDouble("gap_element",KGapElement());
    
    SetWidgetBindingDouble("gate_a_start",KGateAStart());
    SetWidgetBindingDouble("gate_a_end",KGateAEnd());
    
    SetWidgetBindingDouble("gate_b_start",KGateBStart());
    SetWidgetBindingDouble("gate_b_end",KGateBEnd());
    SetWidgetBindingDouble("gate_i_height",KGateIHight());                                    //闸门I高度

    SetWidgetBindingDouble("cscan_interval",KCScanInterval());
    SetWidgetBinding("encoder_delay",KStartParamSpinBox());
    SetWidgetBinding("beam_location",KBeamLocation());                                            //beam位置

    connect(kGateAStart, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_gate_start(0, kGateAStart->value());
    });
    connect(kGateAEnd, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_gate_end(0, kGateAEnd->value());
    });

    connect(kGateBStart, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_gate_start(1, kGateBStart->value());
    });
    connect(kGateBEnd, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_gate_end(1, kGateBEnd->value());
    });

    connect(kStartElement, &QSpinBox::editingFinished, this, [this]() {
        eintik::property::set_element_start(kStartElement->value() - 1);
    });

    connect(kEndElement, &QSpinBox::editingFinished, this, [this]() {
        eintik::property::set_element_end(kEndElement->value() - 1);
    });

    connect(kGapElement, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_gap_element(kGapElement->value());
    });

    connect(kCScanInterval, &QDoubleSpinBox::editingFinished, this, [this]() {
        eintik::property::set_cscan_interval(kCScanInterval->value());
    });

    connect(kStartTypeCombox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
        RecoderStartType type = (index == 0) ? RecoderStartType::kDelayTime : RecoderStartType::kEncoderDistance;
        eintik::property::set_start_type(type);
        this->EmitParameterChanged();
    });

    connect(kStartParamSpinBox, &QSpinBox::editingFinished, this, [this]() {
        eintik::property::set_encoder_delay(kStartParamSpinBox->value());
    });

    connect(kBeamLocation,&QSpinBox::valueChanged,this,[this](){
        eintik::property::set_beam_location(kBeamLocation->value() - 1);
    });
    
    connect(kGateIHight, &QDoubleSpinBox::valueChanged, this, [this]() {
        eintik::property::set_threadhold_gate_i(kGateIHight->value());
    });

    // 初始化JSON文件（若不存在则创建）
    if (!JsonFileExists())
    {
        CreateEmptyJsonFile();
    }

    // 程序启动时加载参数到UI
    LoadParamsFromJson();

    //gate
    property::set_gate_start(0, kGateAStart->value());
    property::set_gate_end(0, kGateAEnd->value());
    property::set_gate_start(1, kGateBStart->value());
    property::set_gate_end(1, kGateBEnd->value());

    //element
    property::set_element_start(kStartElement->value() - 1);
    property::set_element_end(kEndElement->value() - 1);
    property::set_gap_element(kGapElement->value());
    property::set_cscan_interval(kCScanInterval->value());
    
    //encoder delay
    property::set_encoder_delay(kStartParamSpinBox->value());
    RecoderStartType default_start_type = (kStartTypeCombox->currentIndex() == 0) ? RecoderStartType::kDelayTime : RecoderStartType::kEncoderDistance;
    property::set_start_type(default_start_type);
    auto scan_start = kScanStartUs->value();
    auto scan_range = kScanRangeUs->value();
    auto scan_end = scan_start + scan_range;
    property::on_point(scan_start, scan_end, kWaveSpeed->value(),kSampleQty->value());
    
    // beam location,
    property::set_beam_location(kBeamLocation->value() - 1);

    // gate i hight
    property::set_threadhold_gate_i(kGateIHight->value());

    // 关联参数变化信号：当UI值变化时保存到JSON
    connect(this, &ControlPanel::ParameterChanged, this, &ControlPanel::SaveParamsToJson);
}

ControlPanel::~ControlPanel()
{
    delete debounce_timer_;
}

void ControlPanel::OnWidgetValuesChanged() const
{
    debounce_timer_->start();
}

void ControlPanel::EmitParameterChanged()
{
    const auto params = CollectValues();
    emit ParameterChanged(params);
}

void ControlPanel::SetWidgetBinding(const KeyType& key, QSpinBox* box)
{
    spin_bindings_[key] = box;
    connect(box, &QSpinBox::editingFinished, this, &ControlPanel::EmitParameterChanged);
}

void ControlPanel::SetWidgetBindingDouble(const KeyType& key, QDoubleSpinBox* box)
{
    double_bindings_[key] = box;
    connect(box, &QDoubleSpinBox::editingFinished, this, &ControlPanel::EmitParameterChanged);
}

void ControlPanel::OnCollectValues(std::unordered_map<KeyType, ValueType>& params) const
{
    params = CollectValues();
}

void ControlPanel::SaveParamsToJson()
{
    // 1. 收集当前UI所有参数（使用现有CollectValues()方法）
    KeyPairMapType currentParams = CollectValues();

    // 2. 转换为QJsonObject
    QJsonObject jsonObj;
    for (const auto& [key, value] : currentParams)
    {
        // 直接将KeyType（std::string）转换为QString作为JSON键
        QString keyStr = QString::fromStdString(key);  // 关键修正：字符串直接转换
        // 根据ValueType类型存入JSON值
        if (std::holds_alternative<int>(value))
        {
            jsonObj[keyStr] = std::get<int>(value);
        }
        else if (std::holds_alternative<double>(value))
        {
            double doubleVal = std::get<double>(value);
            jsonObj[keyStr] = QJsonValue(doubleVal);
        }
        else if (std::holds_alternative<bool>(value))
        {
            jsonObj[keyStr] = std::get<bool>(value);
        }
        else if (std::holds_alternative<std::string>(value))
        {
            jsonObj[keyStr] = QString::fromStdString(std::get<std::string>(value));
        }
    }

    // 3. 写入文件
    QFile file(GetJsonFilePath());
    if (file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QJsonDocument doc(jsonObj);
        file.write(doc.toJson(QJsonDocument::Indented)); // 格式化输出，便于阅读
        file.close();
    }
}

void ControlPanel::LoadParamsFromJson()
{
    // 若文件不存在，先创建空文件
    if (!JsonFileExists())
    {
        CreateEmptyJsonFile();
        return;
    }

    // 1. 读取JSON文件
    QFile file(GetJsonFilePath());
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return; // 打开失败则使用默认值
    }
    QByteArray data = file.readAll();
    file.close();

    // 2. 解析JSON
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull() || !doc.isObject())
    {
        return; // 解析失败则使用默认值
    }
    QJsonObject jsonObj = doc.object();

    // 3. 刷新到SpinBox控件（整数类型）
    for (const auto& [key, box] : spin_bindings_)
    {
        // 直接将KeyType（std::string）转换为QString，与JSON键匹配
        QString keyStr = QString::fromStdString(key);  // 关键修正
        if (jsonObj.contains(keyStr))
        {
            box->setValue(jsonObj[keyStr].toInt());  // 整数参数
        }
    }

    // 4. 刷新到DoubleSpinBox控件（浮点类型）
    for (const auto& [key, box] : double_bindings_)
    {
        QString keyStr = QString::fromStdString(key);
        if (jsonObj.contains(keyStr))
        {
            double value = jsonObj[keyStr].toDouble();
            box->setValue(value); // 设置到QDoubleSpinBox
        }
    }

    QString startTypeKey = QString::fromStdString("start_type");
    if (jsonObj.contains(startTypeKey))
    {
        int savedIndex = jsonObj[startTypeKey].toInt();
        if (savedIndex >= 0 && savedIndex < kStartTypeCombox->count())
        {
            kStartTypeCombox->setCurrentIndex(savedIndex);
            RecoderStartType type = (savedIndex == 0) ? RecoderStartType::kDelayTime : RecoderStartType::kEncoderDistance;
            eintik::property::set_start_type(type);
        }
    }

    // 保留：加载"encoder_delay"字段，恢复SpinBox值
    QString paramKey = QString::fromStdString("encoder_delay");
    if (jsonObj.contains(paramKey))
    {
        kStartParamSpinBox->setValue(jsonObj[paramKey].toInt());
        eintik::property::set_encoder_delay(jsonObj[paramKey].toInt());
    }
}

QString ControlPanel::GetJsonFilePath() const
{
    // 获取系统AppData目录
    QString appDirPath = QCoreApplication::applicationDirPath();
    QDir appDir(appDirPath);

    QString appDataPath= appDir.filePath("AppData");
    // 创建目录（如果不存在）
    QDir appDataDir(appDataPath);
    if (!appDataDir.exists())
    {
        appDataDir.mkpath(".");
    }
    // 返回完整文件路径（AppData/default_params.json）
    return appDataPath + "/default_params.json";
}

bool ControlPanel::JsonFileExists() const
{
    return QFile::exists(GetJsonFilePath());
}

void ControlPanel::CreateEmptyJsonFile() const
{
    QFile file(GetJsonFilePath());
    if (file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        // 写入空对象
        QJsonObject emptyObj;
        QJsonDocument doc(emptyObj);
        file.write(doc.toJson());
        file.close();
    }
}

ControlPanel::KeyPairMapType ControlPanel::CollectValues() const
{
    KeyPairMapType values;
    for (const auto& [key, box] : spin_bindings_)
    {
        values[key] = box->value();
    }
    for (const auto& [key, box] : double_bindings_)
    {
        values[key] = box->value();
    }
    values["start_type"] = kStartTypeCombox->currentIndex();
    return values;
}

}
